# -*- encoding: utf-8 -*-

"""
------------------------------------------
@File       : singleton.py
@Author     : maixiaochai
@Email      : maixiaochai@outlook.com
@CreatedOn  : 2021/8/23 11:38
------------------------------------------
    单例模式
"""
from functools import wraps


class Singleton:
    """
        方式一：用 __new__ 实现
        __new__，用于生成实例
        __init__，用于初始化实例
    """
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            _instance = super().__new__(cls)

        return cls._instance


class MyClass(Singleton):
    class_val = 22

    def __init__(self, val):
        self.val = val

    def obj_fun(self):
        print(self.val, 'obj_fun')

    @staticmethod
    def static_fun():
        print('staticmethod')

    @classmethod
    def class_fun(cls):
        print(cls.class_val, 'classmethod')


def demo1():
    """
        测试 __new__ 方式的单例模式
    """
    a = MyClass(1)
    b = MyClass(2)
    print("a is b: ", a is b)  # True
    print(f"id-a: {id(a)}, id-b: {id(b)}")  # 4367665424 4367665424
    # 类型验证
    print("type-a: ", type(a))  # <class '__main__.MyClass'>
    print("type-b: ", type(b))  # <class '__main__.MyClass'>


# ========================[ 方法二: 装饰器实现单例模式 ]========================
def singleton(cls):
    _instance = {}

    @wraps(cls)
    def inner(*args, **kwargs):
        if 'cls' not in _instance:
            _instance['cls'] = cls(*args, **kwargs)

        return _instance['cls']

    return inner


@singleton
class Singleton2:
    val = 123

    def __init__(self, x):
        self.x = x


def demo2():
    s = Singleton2(1)
    t = Singleton2(2)
    print(s is t)
    # s.val = 333
    # t.val = 321
    print(s.val, t.val)
    t.x = 2
    print(s.x, t.x)


# ========================[ 方法三: 类装饰器实现单例模式 ]========================
class SingletonPro:
    """
        用类写成的装饰器
    """

    def __init__(self, cls):
        self.cls = cls
        self.ins = None

    def __call__(self, *args, **kwargs):
        if self.ins is None:
            self.ins = self.cls(*args, **kwargs)

        return self.ins


@SingletonPro
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f'{self.name} 的年龄是 {self.age} 岁'


def demo3():
    zhao = Person('zhao', 18)
    sun = Person('sun', 20)

    print(zhao)
    print(sun)


if __name__ == '__main__':
    # demo1()
    # demo2()
    demo3()
